package com.kaguya.vams.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.kaguya.vams.common.constant.Constants;
import com.kaguya.vams.domain.entity.SysMenu;
import com.kaguya.vams.domain.entity.SysRole;
import com.kaguya.vams.domain.entity.SysUser;
import com.kaguya.vams.mapper.SysUserMapper;
import com.kaguya.vams.service.SysMenuService;
import com.kaguya.vams.service.SysRoleService;
import com.kaguya.vams.service.SysUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.kaguya.vams.utils.RedisUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author kaguya
 * @since 2021-07-28
 */
@Slf4j
@Service
public class SysUserServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements SysUserService {

    @Autowired
    private SysRoleService roleService; //角色服务层

    @Autowired
    private SysMenuService menuService; //菜单权限服务层

    @Autowired
    private RedisUtils redisUtils; //redis工具类

    /**
     * 根据用户id获取该用户所有权限集合（角色，菜单）
     *
     * @param userId
     * @return
     */
    @Override
    public String getUserAuthorities(long userId) {

        //权限集合
        String authority = "";

        //获取用户名 作为redis key
        SysUser user = getById(userId);

        //redis key
        String authKey = Constants.AUTHORITY_KEY + user.getUsername();

        //优先从缓存中获取，如果缓存中没有，调用方法从数据库获取
        if (null != redisUtils.getCacheObject(authKey)) {

            log.info("从缓存中获取权限");

            authority = redisUtils.getCacheObject(authKey);

        } else {
            log.info("从数据库中查询获取权限");
            //获取角色
            //根据userId获取到用户角色关联表的roleid
            QueryWrapper<SysRole> wrapper1 = new QueryWrapper<>();
            wrapper1.inSql("id", "select role_id from sys_user_role where user_id =" + userId);
            //根据roleid返回role
            //select *from sys_role where id in (select role_id from sys_user_role where user_id = ?)
            List<SysRole> roles = roleService.list(wrapper1);
            if (roles.size() > 0) {
                //每个字段加上前缀并用,分割
                String roleCodes = roles.stream().map(r -> {
                    return "ROLE_" + r.getCode();
                }).collect(Collectors.joining(","));

                authority = roleCodes;
            }

            //获取菜单操作权限编码
            //根据用户id获取菜单权限id
            List<Long> menuIds = baseMapper.getNavMenuIdByUserId(userId);
            if (menuIds.size() > 0) {
                //获取菜单权限集合

                List<SysMenu> menus = menuService.listByIds(menuIds);

                String menuPerms = menus.stream().map(e -> e.getPerms()).collect(Collectors.joining(","));
                //与获取的角色字符串拼接
                authority = authority.concat(",").concat(menuPerms);
            }
            //log.info("用户id为：{} 的权限为{}",userId,authority);

            //获取后将权限集合存入缓存中
            redisUtils.setCacheObject(authKey, authority, Constants.AUTHORITY_EXPIRATION, TimeUnit.HOURS);
        }

        return authority;
    }

    /**
     * 根据username返回单个user
     *
     * @param username
     */
    @Override
    public SysUser getUserByUserName(String username) {
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.eq("username", username);
        return getOne(wrapper);
    }

    /**
     * 删除某个用户的权限信息
     *
     * @param username
     */
    @Override
    public void clearUserAuthorityInfo(String username) {
        log.info("-----清空用户{}权限缓存",username);
        redisUtils.deleteObject(Constants.AUTHORITY_KEY+username);
    }

    /**
     * 删除某个用户的权限信息
     *
     * @param roleId
     */
    @Override
    public void clearUserAuthorityInfoByRoleId(Long roleId) {
        //根据roleid获取到与其关联的所有用户
        QueryWrapper<SysUser> wrapper = new QueryWrapper<>();
        wrapper.inSql("id","select user_id from sys_user_role where role_id = "+roleId);
        List<SysUser> list = list(wrapper);

        //循环调用方法根据用户名删除权限redis缓存
        list.forEach(e -> {
            this.clearUserAuthorityInfo(e.getUsername());
        });
    }

    /**
     * 删除所有与该菜单相连的所有用户的权限信息
     *
     * @param menuId
     */
    @Override
    public void clearUserAuthorityInfoByMenuId(Long menuId) {
        //调用方法获取所有与该菜单相连的所有用户
        List<SysUser> list = baseMapper.getListByMenuId(menuId);

        //循环根据name删除缓存
        list.forEach( e -> {
            this.clearUserAuthorityInfo(e.getUsername());
        });
    }
}
